use core::ops::Add;
use core::ops::Sub;

use crate::page::Page;

pub mod pagedef;

cfg_if::cfg_if! {
    if #[cfg(target_arch = "aarch64")] {
        mod aarch64;
    } else {
        mod noop;
    }
}

/// 描述内核使用的虚拟地址空间
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct VirtKsymAddr(usize);

impl From<usize> for VirtKsymAddr {
    fn from(value: usize) -> Self {
        Self(value)
    }
}

impl Add<usize> for VirtKsymAddr {
    type Output = VirtKsymAddr;
    fn add(self, rhs: usize) -> Self::Output {
        VirtKsymAddr::from(self.0 + rhs)
    }
}

impl Sub<usize> for VirtKsymAddr {
    type Output = VirtKsymAddr;
    fn sub(self, rhs: usize) -> Self::Output {
        VirtKsymAddr::from(self.0 - rhs)
    }
}

impl Sub<VirtKsymAddr> for VirtKsymAddr {
    type Output = VirtKsymAddr;
    fn sub(self, rhs: VirtKsymAddr) -> Self::Output {
        VirtKsymAddr::from(self.0 - rhs.0)
    }
}

impl VirtKsymAddr {
    #[inline(always)]
    pub fn value(&self) -> usize {
        self.0
    }
}

/// 描述虚拟线性地址空间
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct VirtLmAddr(usize);

impl From<usize> for VirtLmAddr {
    fn from(value: usize) -> Self {
        Self(value)
    }
}

impl Add<usize> for VirtLmAddr {
    type Output = VirtLmAddr;
    fn add(self, rhs: usize) -> Self::Output {
        VirtLmAddr::from(self.0 + rhs)
    }
}

impl Sub<usize> for VirtLmAddr {
    type Output = VirtLmAddr;
    fn sub(self, rhs: usize) -> Self::Output {
        VirtLmAddr::from(self.0 - rhs)
    }
}

impl Sub<VirtLmAddr> for VirtLmAddr {
    type Output = VirtLmAddr;
    fn sub(self, rhs: VirtLmAddr) -> Self::Output {
        VirtLmAddr::from(self.0 - rhs.0)
    }
}

impl VirtLmAddr {
    #[inline(always)]
    pub fn value(&self) -> usize {
        self.0
    }
}

impl Page {
    #[inline(always)]
    pub fn value(&self) -> usize {
        self as *const Self as usize
    }
}

/// 描述物理地址帧号
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PfnAddr(usize);

impl From<usize> for PfnAddr {
    fn from(value: usize) -> Self {
        Self(value)
    }
}

impl Add<usize> for PfnAddr {
    type Output = PfnAddr;
    fn add(self, rhs: usize) -> Self::Output {
        PfnAddr::from(self.0 + rhs)
    }
}

impl Sub<usize> for PfnAddr {
    type Output = PfnAddr;
    fn sub(self, rhs: usize) -> Self::Output {
        PfnAddr::from(self.0 - rhs)
    }
}

impl Sub<PfnAddr> for PfnAddr {
    type Output = PfnAddr;
    fn sub(self, rhs: PfnAddr) -> Self::Output {
        PfnAddr::from(self.0 - rhs.0)
    }
}

impl PfnAddr {
    #[inline(always)]
    pub fn value(&self) -> usize {
        self.0
    }
}

/// 描述物理地址空间
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PhysAddr(usize);

impl From<usize> for PhysAddr {
    fn from(value: usize) -> Self {
        Self(value)
    }
}

impl Add<usize> for PhysAddr {
    type Output = PhysAddr;
    fn add(self, rhs: usize) -> Self::Output {
        PhysAddr::from(self.0 + rhs)
    }
}

impl Sub<usize> for PhysAddr {
    type Output = PhysAddr;
    fn sub(self, rhs: usize) -> Self::Output {
        PhysAddr::from(self.0 - rhs)
    }
}

impl Sub<PhysAddr> for PhysAddr {
    type Output = PhysAddr;
    fn sub(self, rhs: PhysAddr) -> Self::Output {
        PhysAddr::from(self.0 - rhs.0)
    }
}

impl PhysAddr {
    #[inline(always)]
    pub fn value(&self) -> usize {
        self.0
    }

    pub const fn new(value: usize) -> Self {
        Self(value)
    }
}

impl Page {
    #[inline(always)]
    pub fn page_to_pfn(&self) -> PfnAddr {
        self.arch_page_to_pfn()
    }

    #[inline(always)]
    pub fn page_to_phys(&self) -> PhysAddr {
        self.page_to_pfn().pfn_to_phys()
    }

    #[inline(always)]
    pub fn page_to_virtlm(&self) -> VirtLmAddr {
        self.arch_page_to_virtlm()
    }
}

impl PfnAddr {
    #[inline(always)]
    pub fn pfn_to_page(&self) -> &'static Page {
        self.arch_pfn_to_page()
    }

    #[inline(always)]
    pub fn pfn_to_page_mut(&self) -> &'static mut Page {
        self.arch_pfn_to_page_mut()
    }

    #[inline(always)]
    pub fn pfn_to_phys(&self) -> PhysAddr {
        self.arch_pfn_to_phys()
    }
}

impl PhysAddr {
    #[inline(always)]
    pub fn phys_to_virtksym(&self) -> VirtKsymAddr {
        self.arch_phys_to_virtksym()
    }

    #[inline(always)]
    pub fn phys_to_virtlm(&self) -> VirtLmAddr {
        self.arch_phys_to_virtlm()
    }

    #[inline(always)]
    pub fn phys_to_pfn(&self) -> PfnAddr {
        self.arch_phys_to_pfn()
    }

    #[inline(always)]
    pub fn phys_to_pfn_up(&self) -> PfnAddr {
        self.arch_phys_to_pfn_up()
    }

    #[inline(always)]
    pub fn phys_to_pfn_down(&self) -> PfnAddr {
        self.arch_phys_to_pfn_down()
    }

    #[inline(always)]
    pub fn phys_to_page(&self) -> &'static Page {
        self.phys_to_pfn().pfn_to_page()
    }

    #[inline(always)]
    pub fn phys_to_page_mut(&self) -> &'static mut Page {
        self.phys_to_pfn().pfn_to_page_mut()
    }
}

impl VirtKsymAddr {
    #[inline(always)]
    pub fn virtksym_to_phys(&self) -> PhysAddr {
        self.arch_virtksym_to_phys()
    }
}

impl VirtLmAddr {
    #[inline(always)]
    pub fn virtlm_to_phys(&self) -> PhysAddr {
        self.arch_virtlm_to_phys()
    }

    #[inline(always)]
    pub fn virtlm_to_page(&self) -> &'static Page {
        self.arch_virtlm_to_page()
    }

    #[inline(always)]
    pub fn virtlm_to_page_mut(&self) -> &'static mut Page {
        self.arch_virtlm_to_page_mut()
    }
}
